package com.binarycube.webserver.datasource;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import net.sf.json.JSONObject;

import org.apache.log4j.Logger;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import com.binarycube.webserver.config.DatasourceConfig;

public class XMLDataSource extends AbstractDataSource implements IDataSource{

	static Logger log = Logger.getLogger(XMLDataSource.class.getName());

	public List<Record> doQuery() {
		validateParams();
		try {
			String xpath = _config.getProperty("path");
			Reader xmlSource = new FileReader(_config.getProperty("file"));
			_records =  toJSONRecords(xmlSource, xpath);
		} catch (IOException | XPathExpressionException e) {
			log.error("Error querying XML Datasource: " + _config.getName(), e);
		}
		return _records;
	}
	
	
	public void configure(DatasourceConfig config) {
		super.configure(config);
		if (!new File(_config.getProperty("file")).exists()) {
			log.error("Error configuring XML Datasource - file not found: " + _config.getName());
		}
	}

	
	public static List<Record> toJSONRecords(Reader xmlSource, String xpath) throws XPathExpressionException{
		List<Record> records = new ArrayList<Record>();
		XPathFactory factory =  XPathFactory.newInstance();
		XPath xp = factory.newXPath();
		NodeList nodes=    (NodeList) xp.compile(xpath).evaluate( new InputSource(xmlSource), XPathConstants.NODESET);
		if (nodes != null) {
			for (int i = 0; i < nodes.getLength(); i++) {
				Node node = nodes.item(i);
				JSONObject json = toJSON(node);
				//System.out.println(json.toString());
				Record r = Record.JSONRecord();
				r.set(json);
				records.add(r);
			}
		}
		return records;
	}
	
	
	private static JSONObject toJSON(Node node) {
		JSONObject json = new JSONObject();
		if (node.hasAttributes()) {
			NamedNodeMap nnm = node.getAttributes();
			for (int i =0 ; i < nnm.getLength(); i++) {
				json.accumulate("@" + nnm.item(i).getLocalName(), nnm.item(i).getNodeValue());
			}
		}
		if (node.getNodeType() == Node.TEXT_NODE) json.accumulate("#", node.getTextContent());
		Node child = node.getFirstChild();
		while (child != null) {
			if (child.getNodeType() == Node.ELEMENT_NODE) {
				if ((child.getFirstChild() != null) && (child.getFirstChild().getNodeType() == Node.TEXT_NODE)) {
					json.accumulate(child.getLocalName(), child.getFirstChild().getNodeValue());
				} else json.accumulate(child.getLocalName(), toJSON(child));
			} else if (child.getNodeType() == Node.TEXT_NODE) {
				String value = child.getNodeValue().trim();
				if ((value != null) && (!value.equals(""))) json.accumulate("#text", value);
			}
			
			child = child.getNextSibling();
		}
		return json;
	}


	
	
	
}
